/*
 * @Author: 大D
 * @email: 857216393@qq.com
 * @Date: 2023-12-25 14:39:56
 * @Description: 封装axios类  以便实例多种axios请求 axios@1.6.2
 */

import axios from 'axios';
import type { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
import type { IAxiosRequestConfig, Iinterceptors } from '@/apis/request/type';
// 引入loading
import loading from '@/utils/loading';
// 引入进度条
import nprogress from 'nprogress';
// 引入进度条样式
import 'nprogress/nprogress.css';
nprogress.configure({ showSpinner: false });
// 引入错误码
import { checkStatus } from './checkStatus';
// 引入请求取消
import { AxiosCancel } from './axiosCancel';
const axiosCancel = new AxiosCancel();
//在当前模块引入store
import { useUserStore } from '@/stores/userStore.js';

export class AxiosClass {
  private instance: AxiosInstance;
  private interceptorsObj?: Iinterceptors;
  private showLoading?: boolean;
  private cancel?: boolean;
  constructor(config: IAxiosRequestConfig) {
    this.instance = axios.create(config);
    this.interceptorsObj = config.interceptors;
    this.showLoading = config?.showLoading;
    this.interceptors();
  }
  // 封装拦截器
  private interceptors() {
    // 全局请求拦截器
    this.instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
      // 请求进度条
      nprogress.start();
      // 请求loading  默认添加
      this.showLoading ?? (this.showLoading = true);
      this.showLoading && loading.show();
      // 处理 get delete请求参数params = data
      if (
        config.method == 'get' ||
        config.method == 'GET' ||
        config.method == 'DELETE' ||
        config.method == 'delete'
      ) {
        config.params ?? (config.params = config.data);
      }
      // 取消重复请求  默认
      this.cancel ?? (this.cancel = true);
      this.cancel && axiosCancel.addPending(config);
      //判断需要携带token带给服务器、
      const userStore = useUserStore();
      if (userStore.getToken()) {
        config.headers.token = userStore.getToken();
      }
      return config;
    });
    // 全局响应拦截器
    this.instance.interceptors.response.use(
      res => {
        nprogress.done();
        this.showLoading && loading.hide();
        // 移除取消函数
        const { config } = res;
        axiosCancel.removePending(config);
        if (res.data.code != 200) {
          ElMessage.error(res.data.msg);
        }
        return res.data;
      },
      error => {
        nprogress.done();
        axiosCancel.removePending(error.config);
        const { response } = error;
        // 请求超时 && 网络错误单独判断，没有 response
        if (error.message.indexOf('timeout') !== -1) ElMessage.error('请求超时！请您稍后重试');
        if (error.message.indexOf('Network Error') !== -1)
          ElMessage.error('网络错误！请您稍后重试');
        // 根据服务器响应的错误状态码，做不同的处理
        if (response) checkStatus(response.status);
        this.showLoading && loading.hide();
        return error;
      }
    );
    // 实例拦截器
    this.instance.interceptors.request.use(
      this.interceptorsObj?.request,
      this.interceptorsObj?.requestCatch
    );
    // 实例响应器
    this.instance.interceptors.response.use(
      this.interceptorsObj?.response,
      this.interceptorsObj?.responseCatch
    );
  }
  // request请求
  request<T>(config: IAxiosRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.showLoading = config.showLoading;
      this.cancel = config.cancel;
      if (config.interceptors?.request) {
        config = config.interceptors?.request(config as InternalAxiosRequestConfig);
      }
      this.instance.request<any, T>(config).then(
        res => {
          if (config.interceptors?.response) {
            res = config.interceptors?.response(res);
          }
          resolve(res);
        },
        error => {
          return reject(error);
        }
      );
    });
  }
  get<T>(config: IAxiosRequestConfig) {
    return this.request<T>({ ...config, method: 'get' });
  }
  post<T>(config: IAxiosRequestConfig) {
    return this.request<T>({ ...config, method: 'post' });
  }
  put<T>(config: IAxiosRequestConfig) {
    return this.request<T>({ ...config, method: 'put' });
  }
  delete<T>(config: IAxiosRequestConfig) {
    return this.request<T>({ ...config, method: 'delete' });
  }
  patch<T>(config: IAxiosRequestConfig) {
    return this.request<T>({ ...config, method: 'patch' });
  }
}
